#include base
#include bool


(defmacro* match-list (xs (:list (:literal ()) (:rest empty-body))
                          (:list (:list car cdr) (:rest cons-body)))
  `(if (empty? ,xs)
     (seq ,@empty-body)
     (let ((,car (head ,xs))
	   (,cdr (tail ,xs)))
       ,@cons-body)))

(defun .. (a b)
  (if (< a b)
      (cons a (.. (+ 1 a) b))
    '()))

(defun ... (a b)
  (if (<= a b)
      (cons a (... (+ 1 a) b))
    '()))

(defun map (f xs)
  (match-list xs
    (() '())
    ((x xs)
       (cons (f x)
	     (map f xs)))))

(defun fold-left (folder x ys)
  (match-list ys
    (() x)
    ((y ys)
     (fold-left folder (folder x y) ys))))

(defun fold-right (folder ys x)
  (match-list ys
    (() x)
    ((y ys)
     (folder y (fold-right folder ys x)))))

(defun filter (pred xs)
  (fold-right (lambda (x acc)		
	        (if (pred x)
		    (cons x acc)
		  acc))
	      xs
	      '()))

(defun all? (pred xs)
  (match-list xs
    (() #t)
    ((x xs)
     (and (pred x) (all? pred xs)))))

(defun any? (pred xs)
  (match-list xs
    (() #f)
    ((x xs)
     (or (pred x) (any? pred xs)))))

(defun length (xs)
  (fold-left (lambda (acc x) (+1 acc)) 0 xs))

(defun sum (xs)
  (fold-left + 0 xs))
